﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using IdeaNMR.Shared.Utils;

namespace IdeaNMR.Web.Core
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <remarks>
    /// <para>Ids are assigned to the objects when objects are saved to the database.</para>
    /// </remarks>
    [Serializable]
    public class HardObjectFacade<T> : BaseObjectFacade<T>
        where T : HardObject, IHardObjectRelations, new()
    {
        /// <summary>
        /// Get a copy of Content - detached, relations are filtered by username.
        /// </summary>
        /// <returns></returns>
        protected override T GetContent()
        {
            T result = base.GetContent();

            if (this.Content == null)
            {
                // Watch here that result does not get attached to any object context
                // e.g. does not assign user entity that is attached to object context
                Type coT = typeof(T);
                if (coT == typeof(Sample))
                    result.Script = EmbeddedPythonScripts.LoadScript("Sample.py");
                else if(coT == typeof(Spectrometer))
                    result.Script = EmbeddedPythonScripts.LoadScript("Spectrometer.py");

                result.User = new User();
                this.User.CopyTo(result.User, true);
            }
            else
            {
                T first = new T();

                if (!this.Content.FirstVersionReference.IsLoaded)
                    this.Content.FirstVersionReference.Load();
                this.Content.FirstVersion.CopyTo(first, true);

                if (!this.Content.FirstVersion.DerivedVersions.IsLoaded)
                    this.Content.FirstVersion.DerivedVersions.Load();

                // Get all the versions and Identify the one, that corresponds to this.Content
                T version;
                var userVersions = this.Content.FirstVersion.DerivedVersions.
                                        OfType<T>().
                                        Where(vv => 
                                            {
                                                if (!vv.UserReference.IsLoaded) vv.UserReference.Load();
                                                return  vv.User.Username == this.Username || !vv.IsPrivate; 
                                            });
                foreach (T v in userVersions)
                {
                    version = new T();
                    v.CopyTo(version, true);
                    first.DerivedVersions.Add(version);

                    if (v == this.Content)
                    { 
                        result = version;
                        result.User = new User();
                        v.User.CopyTo(result.User, true);
                    }
                }
            }
            return result;
        }

        public HardObjectFacade(string username)
            : base(username)
        { }
        public HardObjectFacade(Guid targetID, string username)
            : this(username)
        {
            this.LoadById(targetID);
        }

        protected override void CreateRelationships(T obj, SaveModeOptions smo)
        {
            obj.User = this.User;
        }

        protected override void LoadById(Guid TargetID)
        {
            if (TargetID == Guid.Empty)
                throw new ArgumentException("TargetID should not be empty.");

            this.Content = (from T lr in this.Inmr.BaseObjects.OfType<T>()
                            where lr.Id == TargetID &&
                                  (lr.User.Username == this.Username || lr.IsPrivate == false)
                            select lr).FirstOrDefault();

            if (this.Content == null)
            {
                string err = string.Format("There is not {0} for given Id: {{{1}}} and username '{2}'.", typeof(T).ToString(), TargetID, this.Username);
                throw new ApplicationException(err);
            }
        }

        public override bool isUserAnAuthor(string userName)
        {
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("userName must be non empty string.");

            if (!this.Content.UserReference.IsLoaded) this.Content.UserReference.Load();

            return this.Content.User.Username == userName;
        }
    }
}
